package com.taomus.mytools.lang.groovy;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.LinkedHashMap;
import java.util.Map;

import org.codehaus.groovy.control.CompilationFailedException;
import org.codehaus.groovy.runtime.IOGroovyMethods;

import com.taomus.mytools.lang.exception.GetClassException;
import com.taomus.mytools.lang.exception.InstanceException;
import com.taomus.mytools.lang.inter.DSLangUtils;
import com.taomus.mytools.lang.inter.IMethod;

import groovy.lang.GroovyClassLoader;
import groovy.lang.GroovyClassLoader.InnerLoader;
import groovy.lang.GroovyCodeSource;
import groovy.lang.GroovyObject;

public final class GroovyUtils extends DSLangUtils {
	/**
	 * 类加载器
	 */
	private final static ClassLoader parentLoader = Thread.currentThread().getContextClassLoader();
	private Class<?> objCl = null;
	/**
	 * Groovy 文件池 key : 文件名 value : 文件路径
	 */
	private final static Map<String, Class<?>> gcPool = new LinkedHashMap<String, Class<?>>();

	public GroovyUtils() {
	}

	public GroovyUtils(boolean isCache) {
		this.isCache = isCache;
	}

	/**
	 * 获取 Groovy 实例
	 * 
	 * @param name
	 * @return GroovyObject
	 * @throws CompilationFailedException
	 * @throws IOException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 */
	@Override
	public IMethod newInstance(String name, boolean isCache) throws InstanceException, GetClassException {
		try {
			Class<?> cc = null;
			if (!name.endsWith(".groovy")) {
				throw new InstanceException("Not a Groovy file");
			}
			String key = name.substring(name.lastIndexOf("/") + 1, name.length()).replace(".groovy", "").trim();
			if (isCache && gcPool.containsKey(key)) {
				cc = gcPool.get(name.trim());
			} else {
				cc = this.getClass(name.trim());
				gcPool.put(key, cc);
			}
			if (cc != null) {
				objCl = cc;
				GroovyObject obj = (GroovyObject) cc.newInstance();
				return new GroovyMethod(obj);
			}
			return null;
		} catch (InstantiationException e) {
			throw new InstanceException(e);
		} catch (IllegalAccessException e) {
			throw new InstanceException(e);
		}
	}

	/**
	 * 获取 Groovy Class
	 * 
	 * @param name
	 * @return Class<?>
	 * @throws CompilationFailedException
	 * @throws IOException
	 */
	@Override
	public Class<?> getClass(String name) throws GetClassException {
		try {
			InputStream input = null;
			if (name.endsWith(".groovy")) {
				input = new FileInputStream(new File(name));
			}
			GroovyClassLoader gl = new GroovyClassLoader(parentLoader);
			InnerLoader il = new InnerLoader(gl);
			String scriptText = IOGroovyMethods.getText(input);
			GroovyCodeSource c = new GroovyCodeSource(scriptText, name + ".groovy", "/groovy/script");
			Class<?> ret = il.parseClass(c);
			il.close();
			input.close();
			return ret;
		} catch (CompilationFailedException e) {
			throw new GetClassException(e);
		} catch (IOException e) {
			throw new GetClassException(e);
		}
	}

	public Class<?> getGroovyClass() {
		return objCl;
	}

}
